package com.geek.gkpush.framework.retry.action;

import com.geek.gkpush.framework.retry.RetryMsgPersistFacade;
import com.geek.gkpush.framework.retry.util.CalcNextExecTimeUtils;
import com.geek.gkpush.framework.retry.enums.ExecStatusEnum;
import com.geek.gkpush.framework.retry.model.*;
import com.geek.gkpush.util.str.StringCutUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * <h1>重试消息更新处理类。</h1><br/>
 *
 * <h1><br/><a href="https://u.geekbang.org/subject/arch3/100614201">Java 业务架构实战营：https://u.geekbang.org/subject/arch3/100614201</a></h1><br/><h1><a href="https://gitee.com/ylimhhmily/BizArchPracticeCamp">Java 业务架构实战营代码地址：https://gitee.com/ylimhhmily/BizArchPracticeCamp</a></h1><br/><h1><a href="https://u.geekbang.org/subject/java4th/1001148?source=app_share">高级 Java 工程体系课 2023 版：https://u.geekbang.org/subject/java4th/1001148?source=app_share</a></h1><br/><h1><a href="https://time.geekbang.org/column/intro/100312101?tab=catalog">Dubbo 源码剖析与实战：https://time.geekbang.org/column/intro/100312101?tab=catalog</a></h1>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2023/10/3 09:47
 */
@Component
public class RetryMsgUpdateAction {

    @Autowired
    private RetryMsgPersistFacade retryMsgPersistFacade;

    /**
     * <h2>保存重试消息至数据库。</h2>
     *
     * @param: retryMsgDTO
     * @return: void
     */
    public void saveRetryMsg(RetryMsgDTO retryMsgDTO) {
        retryMsgPersistFacade.saveRetryMsg(retryMsgDTO);
    }

    /**
     * <h2>通过 bizValue + bizType 查询数据。</h2>
     *
     * @param: bizValue
     * @param: bizType
     * @return: com.geek.gkpush.framework.retry.model.RetryMsgDTO
     */
    public RetryMsgDTO queryRetryMsg(String bizValue, String bizType) {
        return retryMsgPersistFacade.queryByBizValueBizType(bizValue, bizType);
    }

    /**
     * <h2>尝试加锁，改为执行中状态。</h2>
     *
     * @param: task
     * @return: boolean
     */
    public boolean tryLock(RetryDelayModel task) {
        RetryMsgUpdateModel model = new RetryMsgUpdateModel();

        model.setId(task.getId());
        model.setBizId(task.getBizId());

        model.setBizValue(task.getBizValue());
        model.setBizType(task.getBizType());

        model.setExecTimes(task.getExecTimes() + 1);
        model.setExecStatus(ExecStatusEnum.ING.getCode());
        model.setSrcExecStatus(task.getExecStatus());
        model.setExecResult(ExecStatusEnum.ING.getMsg());


        // 执行更新逻辑
        return retryMsgPersistFacade.updateExecStatusByCondition(model) > 0;
    }

    /**
     * <h2>更新为成功。</h2>
     *
     * @param: task
     * @return: boolean
     */
    public boolean update2Succ(RetryDelayModel task, String srcExecStatus) {
        RetryMsgUpdateModel model = new RetryMsgUpdateModel();

        model.setId(task.getId());
        model.setBizId(task.getBizId());

        model.setBizValue(task.getBizValue());
        model.setBizType(task.getBizType());

        model.setExecStatus(ExecStatusEnum.SUCC.getCode());
        model.setSrcExecStatus(srcExecStatus);
        model.setExecResult(ExecStatusEnum.SUCC.getMsg());

        // 执行更新逻辑
        return retryMsgPersistFacade.updateExecStatusByCondition(model) > 0;
    }

    /**
     * <h2>更新为失败。</h2>
     *
     * @param: task
     * @return: boolean
     */
    public RetryMsgUpdateModel update2Fail(RetryDelayModel task, RetryResult retryResult) {
        RetryConfigModel retryConfig = retryMsgPersistFacade.getRetryConfig(task.getBizType());

        RetryMsgUpdateModel model = new RetryMsgUpdateModel();

        model.setId(task.getId());
        model.setBizId(task.getBizId());

        model.setBizValue(task.getBizValue());
        model.setBizType(task.getBizType());

        model.setExecStatus(ExecStatusEnum.FAIL.getCode());
        model.setSrcExecStatus(retryResult.getSrcExecStatus());
        if (StringUtils.isEmpty(retryResult.getExceptionMsg())) {
            model.setExecResult(ExecStatusEnum.FAIL.getMsg());
        } else {
            model.setExecResult(StringCutUtils.cut(retryResult.getExceptionMsg(), 1800));
        }

        model.setLastExecTime(task.getExecStartTime());
        Date nextExecTime = CalcNextExecTimeUtils.calcNextExecTime(
                task.getExecTimes(),
                retryConfig.getNextRetryAlgoType(),
                retryConfig.getNextRetryAlgoCfg());
        model.setNextExecTime(nextExecTime);

        // 执行更新逻辑
        return retryMsgPersistFacade.updateExecStatusByCondition(model) > 0 ? model : null;
    }
}